
#ifndef PARATREEMODEL_H
#define PARATREEMODEL_H

/*
    右下角的树状视图
    每个node存三个属性：name名字，para参数，type_id参数类型的枚举值
*/

#include <ui/tree/ParaTreeNode.h>

#include <QAbstractItemModel>
#include <QObject>
#include <QSharedPointer>

#include <unordered_set>

#include <boost/json.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>

namespace solar
{
    class Para;
    class ParaTreeNode;
    class Sun;
    class Location;
    class Air;
    class Terrain;
    class Camera;
    class Cloud;
    class Node;
    class Heliostat;
    class Receiver;
    class Ordinary;

    enum TreeModelType
    {
        LOCATION,
        SUN,
        AIR,
        TERRAIN,
        CAMERA,
        CLOUD, // 右下角，worldPara设置部分
        NODE,
        HELIOSTAT,
        RECEIVER,
        ORDINARY // 右下角，scenePara设置部分
    };

    class ParaTreeModel : public QAbstractItemModel
    {
            Q_OBJECT

            enum nodeRoles
            {
                NAME = Qt::UserRole + 1,
                PARA,

            };

        public:
            ParaTreeModel(TreeModelType _model_type, QSharedPointer<Para> _para = nullptr,
                          QObject* parent = nullptr);
            ~ParaTreeModel() override;

            /**
             * 通过boost::property_tree::ptree tree对paratreemodel的参数进行设置
             */
            void setParaViaPTree(boost::property_tree::ptree tree);
            void updateParaViaPTree(ParaTreeNode* parent_node, int k,
                                    boost::property_tree::ptree tree, std::string name,
                                    int xyz = 1);

            [[nodiscard]] auto
            columnCount(const QModelIndex& parent = QModelIndex()) const -> int override;
            [[nodiscard]] auto
            rowCount(const QModelIndex& parent = QModelIndex()) const -> int override;
            [[nodiscard]] auto roleNames() const -> QHash<int, QByteArray> override;
            [[nodiscard]] auto data(const QModelIndex& index, int role) const -> QVariant override;
            [[nodiscard]] auto flags(const QModelIndex& index) const -> Qt::ItemFlags override;
            [[nodiscard]] auto
            index(int row, int column,
                  const QModelIndex& parent = QModelIndex()) const -> QModelIndex override;
            [[nodiscard]] auto parent(const QModelIndex& index) const -> QModelIndex override;

            [[nodiscard]] auto getRootNode() const -> QSharedPointer<ParaTreeNode>;

            // 需要实现的虚函数----目前没有使用
            auto removeRows(int row, int count,
                            const QModelIndex& parent = QModelIndex()) -> bool override;
            auto insertRows(int row, int count,
                            const QModelIndex& parent = QModelIndex()) -> bool override;

            // 右下角的视图，只需要编辑、选择，不需要增加/删除节点
            //        void appendChild(const QModelIndex& index, QList<QVariant> dataList,
            //                         int count);
            //        void appendChild(const QModelIndex& index,
            //                         QList<QSharedPointer<ParaTreeNode>> childNodes,
            //                         int count); // 添加一系列孩子
            // 设置index这一节点的属性数据为value
            void setNodePara(QModelIndex index, QVariant value);
            // 获取index这一节点的para数据,注意这里一直返回string
            static auto getNodePara(const QModelIndex& index) -> QString;

            static auto isNodeEditable(const QModelIndex& index) -> bool;
            static auto isNodeOptional(const QModelIndex& index) -> bool;
            // 获得这一节点的所有option
            static auto getNodeOptionList(const QModelIndex& index) -> QList<QString>;
            // 做出选择
            void makeChoice(const QModelIndex& index, const QString& option);
            void makeChoice(ParaTreeNode*& click_node, const QString& option);

            // 返回对应的节点中，当前选中的选项在选项列表中的下标
            static auto getCurrentOptionId(const QModelIndex& index) -> int;

            // 设置/获得paratreemodel的label属性
            void setLabelTxt(QString label_txt);
            auto getLabelTxt() -> QString;

            // 获取para指针
            auto getParaPtr() -> Para*;

            // 获取model_type
            constexpr auto getModelType() -> int { return (int)model_type; }

            //----------------用于测试-----------------------
            void printIndexInfo(QModelIndex index);

            // 建立参数----这部分也可能会更改
        private:
            // 建立的新节点：data1：name，data2：para
            // 建立节点，若parent_state为OPTIONAL，则新创立的节点放到parent节点的option_childnodes[parent_option]列表内，
            // 若同时is_current_option_child为true，则把心窗里的节点放在option_childnodes下的同时，也放到child_nodes下
            // 注意：parent_state是通过parent->getState()获得的
            auto createNode(const QSharedPointer<ParaTreeNode>& parent, const QVariant& data1,
                            const QVariant& data2, ParaState state = QUIET,
                            bool is_current_option_child = false,
                            const QString& parent_option = "") -> QSharedPointer<ParaTreeNode>;
            // // 初始化节点的
            // void initNodeOptions(QList<QString> options);

            /**
             * !!!!!!!!!!!!!!!!!!更改
             */
            void buildSunTreeModel(QSharedPointer<Sun> sun);
            void buildLocationTreeModel(QSharedPointer<Location> location);
            void buildAirTreeModel(QSharedPointer<Air> air);
            void buildTerrainTreeModel(QSharedPointer<Terrain> terrain);
            void buildCameraTreeModel(QSharedPointer<Camera> camera);
            void buildCloudTreeModel(QSharedPointer<Cloud> cloud);
            void buildNodeTreeModel(QSharedPointer<Node> node);
            void buildHeliostatTreeModel(QSharedPointer<Heliostat> heliostat);
            void buildReceiverTreeModel(QSharedPointer<Receiver> receiver);
            void buildOrdinaryTreeModel(QSharedPointer<Ordinary> ordinary);

            // 更新para指针中的某个属性
            /**
             * 这里valu的类型是std::string，是因为para及其派生类都不能用qt中的类型，这里先转化为std::string，在后面的函数中无需再进行转化
             */
            void updatePara(QModelIndex index, const std::string& value);
            // void updateSunPara(QModelIndex index, std::string value);
            void updateSunPara(ParaTreeNode*& click_node, const std::string& value);
            void updateLocationPara(ParaTreeNode*& click_node, const std::string& value);
            void updateAirPara(ParaTreeNode*& click_node, const std::string& value);
            void updateCameraPara(ParaTreeNode*& click_node, const std::string& value);
            void updateTerrainPara(ParaTreeNode*& click_node, const std::string& value);
            void updateCloudPara(ParaTreeNode*& click_node, const std::string& value);
            void updateNodePara(ParaTreeNode*& click_node, const std::string& value);
            void updateHeliostatPara(ParaTreeNode*& click_node, const std::string& value);
            void updateReceiverPara(ParaTreeNode*& click_node, const std::string& value);
            void updateOrdinaryPara(ParaTreeNode*& click_node, const std::string& value);

            QSharedPointer<ParaTreeNode> root_node; // 树状视图中的根节点

            TreeModelType model_type;
            QSharedPointer<Para> para;

            QString label_txt; // 存储右下方树状结构的名字，即label的内容
            QHash<int, QByteArray> role_names_; // 即roleNames

            // ！！！！！！！！！！先这样写着
            std::unordered_set<std::string> sun_position_keys = {"azimuth", "elevation", "dni",
                                                                 "trackable"};
    };

} // namespace solar

#endif // PARATREEMODEL_H
